package cn.liziguo.tank.script.player;

import cn.liziguo.tank.TankGameApplication;
import cn.liziguo.tank.buff.InvincibleEffect;
import cn.liziguo.tank.config.GameConfig;
import cn.liziguo.tank.constants.GameEnum;
import cn.liziguo.tank.constants.SpawnsConst;
import cn.liziguo.tank.factory.BulletFactory;
import cn.liziguo.tank.factory.ItemFactory;
import cn.liziguo.tank.factory.MapFactory;
import cn.liziguo.tank.factory.TankFactory;
import cn.liziguo.tank.script.BaseTankComponent;
import cn.liziguo.tank.script.GameOverComponent;
import cn.liziguo.tank.util.CollidingUtils;
import cn.liziguo.tank.util.CoordinateUtils;
import cn.liziguo.tank.vector.Vector2;
import com.almasb.fxgl.core.math.FXGLMath;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.input.*;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.util.Duration;
import org.jetbrains.annotations.NotNull;

/**
 * @author Liziguo
 * @date 2022/7/8 14:04
 */
public class PlayerComponent extends BaseTankComponent {


    /**
     * 判断这一帧是否需要移动
     */
    public boolean isMove;
    public boolean isShoot;
    public boolean isSkill;

    private TriggerListener triggerListener;

    public PlayerComponent() {
        super(GameConfig.PLAYER_SHOOT_CD, GameConfig.PLAYER_SKILL_CD);
        speed = GameConfig.PLAYER_SPEED;
    }

    /**
     * 组件被添加到实体时会调用
     */
    @Override
    public void onAdded() {
//        effectComponent.startEffect(new InvincibleEffect(Duration.UNKNOWN));

        Input input = FXGL.getInput();
        triggerListener = new TriggerListener() {

            @Override
            protected void onActionBegin(@NotNull Trigger trigger) {
                if (trigger.isKey()) {
                    var key = ((KeyTrigger) trigger).getKey();
                    switch (key) {
                        case F1 -> effectComponent.startEffect(new InvincibleEffect(Duration.UNKNOWN));
                        case F2 -> giveSpeeding();
                        case F3 -> giveArmedShip();
                        case F4 -> bulletLevelUp();
                        case F5 -> skillCount = Integer.MAX_VALUE;
                        case F6 -> {
                            skillCount = 0;
                            bulletLevel = GameConfig.BULLET_LEVEL_DEFAULT;
                            effectComponent.endAllEffects();
                        }
                        case F7 -> {
                            TankGameApplication appCast = FXGL.getAppCast();

                            appCast.levelUp();
                            MapFactory.MapEntity[] mapEntities = appCast.loadLevelMap();
                            if (mapEntities == null) {
                                appCast.resetLevel();
                                mapEntities = appCast.loadLevelMap();
                            }
                            TankGameApplication.clearGameWord();
                            appCast.initLevel(mapEntities);
                        }
                        case F8 -> TankGameApplication.clearGameWord();
                        case F9 -> ItemFactory.createRandomItem();
                        case F10 -> {
                            final String mark = "mark";
                            final int row = 10;
                            final int columns = 2;
                            for (int i = -row; i <= row; i++) {
                                for (int j = 0; j < columns; j++) {
                                    Point2D point2D = CoordinateUtils.local2Word(entity, i * GameConfig.MAP_UNIT, -3 * GameConfig.MAP_UNIT - j * GameConfig.MAP_UNIT);
                                    int x = (int) point2D.getX() / GameConfig.MAP_UNIT * GameConfig.MAP_UNIT;
                                    int y = (int) point2D.getY() / GameConfig.MAP_UNIT * GameConfig.MAP_UNIT;
                                    FXGL.getGameWorld().getEntitiesAt(new Point2D(x, y)).stream().filter(e -> e.getPropertyOptional(mark).isPresent()).forEach(Entity::removeFromWorld);
                                    FXGL.spawn(SpawnsConst.STONE, new SpawnData(x, y).put(mark, true));
                                }
                            }
                        }
                        case F11 -> {
                            do {
                                Entity entity = TankFactory.createEnemy();
                                Point2D point2D = FXGLMath.randomPoint(new Rectangle2D(0, 0, GameConfig.WIDTH - GameConfig.TANK_UNIT - 1, GameConfig.HEIGHT - GameConfig.TANK_UNIT - 1));
                                entity.setPosition(point2D);
                                if (CollidingUtils.isColliding(entity, FXGL.getGameWorld().getGroup(BaseTankComponent.NOT_ARMED_SHIP).getEntitiesCopy()) != null) {
                                    entity.removeFromWorld();
                                } else {
                                    break;
                                }
                            } while (true);
                        }
                        case F12 -> {
                            FXGL.getGameWorld().getGroup(GameEnum.ENEMY).getEntitiesCopy().forEach(enemy -> BaseTankComponent.getTankComponent(enemy).skillCount = Integer.MAX_VALUE);
                        }
                    }
                }
            }

            @Override
            protected void onAction(@NotNull Trigger trigger) {
                if (trigger.isKey()) {
                    // 请不要在此处监听shift和alt
                    var keyTrigger = (KeyTrigger) trigger;
                    // key is being pressed now
                    var key = keyTrigger.getKey();
                    switch (key) {
                        case W -> up();
                        case S -> down();
                        case A -> left();
                        case D -> right();
                        case SPACE -> isShoot = true;
                        case E -> isSkill = true;
                        case NUMPAD0 -> {
//                            EffectsFactory.createBoom(CoordinateTransformation.local2WordMath(entity, 0, -20));
                            Point2D point2D = CoordinateUtils.word2Local(entity, GameConfig.WIDTH / 2, GameConfig.HEIGHT / 2);
                            Point2D point2D1 = CoordinateUtils.word2LocalMath(entity, GameConfig.WIDTH / 2, GameConfig.HEIGHT / 2);
                            System.out.println("local" + point2D);
                            System.out.println("math" + point2D1);
                        }
                        case LEFT -> entity.rotateBy(-1);
                        case RIGHT -> entity.rotateBy(1);
                    }
                } else {
                    var mouseTrigger = (MouseTrigger) trigger;
                    var btn = mouseTrigger.getButton();
                }
            }
        };
        input.addTriggerListener(triggerListener);

    }

    @Override
    public void onRemoved() {
        FXGL.getInput().removeTriggerListener(triggerListener);
    }

    @Override
    public void underAttack(int attack) {
        super.underAttack(attack);
        if (healthIntComponent.isZero()) {
            FXGL.entityBuilder().with(new GameOverComponent()).buildAndAttach();
        }
    }

    @Override
    public void onUpdate(double tpf) {
        // 先执行键盘监听再执行update
        if (isMove) {
            moveForward();
        }
        if (isShoot) {
            shoot();
        }
        if (isSkill) {
            skill();
        }
        isMove = false;
        isShoot = false;
        isSkill = false;

    }

    public void up() {
        entity.setRotation(0);
        vector = Vector2.UP;
        isMove = true;
    }

    public void down() {
        entity.setRotation(180);
        vector = Vector2.DOWN;
        isMove = true;
    }

    public void left() {
        entity.setRotation(-90);
        vector = Vector2.LEFT;
        isMove = true;
    }

    public void right() {
        entity.setRotation(90);
        vector = Vector2.RIGHT;
        isMove = true;
    }

    @Override
    public void onShoot() {
        BulletFactory.createPlayerBullet(this);
    }

    @Override
    public void onSkill() {
        BulletFactory.createPlayerBulletPlus(this);
    }

}
